
/**
 * todo:
 * Error(from carrier57936662):Cannot read property 'store' of undefined
 *  TypeError: Cannot read property 'store' of undefined
 *  at getCapacity (main:1013:22)
 *  at getFreeCapacity (main:1004:12)
 *  at getActualFreeCapacity (main:1007:12)
 *  at transportResource (main:1095:51)
 *  at Object.run (main:1283:19)
 *  at creepWork (main:1689:27)
 *  at GroupCarriers.creepRun (main:1575:15)
 *  at GroupCarriers.run (main:1656:22)
 *  at GroupWorkers.run (main:4035:27)
 *  at ClusterIndependent.run (main:4829:30)
 */

/**
 * 
 * @param {AnyStoreStructure|AnyCreep} haveStore 
 * @param {ResourceConstant} resourceType 
 * @returns {Number}
 */
export function getFreeCapacity(haveStore, resourceType = RESOURCE_ENERGY, actual = false){
    if(haveStore instanceof Resource){
        return 0;
    }
    return getCapacity(haveStore, resourceType) - getResourceAmount(haveStore, resourceType, actual);
}
export function getActualFreeCapacity(haveStore, resourceType = RESOURCE_ENERGY){
    return getFreeCapacity(haveStore, resourceType, true);
}
export function getCapacity(haveStore, resourceType = RESOURCE_ENERGY){
    if(haveStore instanceof Resource){
        return haveStore.resourceType === resourceType ? haveStore.amount : 0;
    }
    return haveStore.store.getCapacity(resourceType);
}
/**
 * 
 * @param {AnyStoreStructure|AnyCreep} haveStore 
 * @returns {Number}
 */
export function getResourceAmount(haveStore, resourceType = RESOURCE_ENERGY, actual = false){
    if(actual){
        let ans;
        if(haveStore instanceof Resource){
            ans = haveStore.resourceType===resourceType?haveStore.amount:0;
        }else{
            ans = haveStore.store[resourceType];
        }
        return ans;
    }

    if(haveStore.__store === undefined){
        haveStore.__store = {};
    }
    if(haveStore.__store[resourceType] !== undefined){
        return haveStore.__store[resourceType];
    }

    let ans;
    if(haveStore instanceof Resource){
        ans = haveStore.resourceType===resourceType?haveStore.amount:0;
    }else{
        ans = haveStore.store[resourceType];
    }

    return haveStore.__store[resourceType] = ans;
}
export function getActualResourceAmount(haveStore, resourceType = RESOURCE_ENERGY){
    return getResourceAmount(haveStore, resourceType, true);
}

export function setResourceAmount(haveStore, amount, resourceType = RESOURCE_ENERGY, actual = false){
    if(actual){
        if(haveStore instanceof Resource){
            if(haveStore.resourceType === resourceType){
                return haveStore._amount = amount;
            }
            return 0;
        }
        return haveStore.store[resourceType] = amount;
    }

    if(!haveStore.__store){
        haveStore.__store = {};
    }
    // if(!haveStore.__store[resourceType]){
    //     haveStore.__store[resourceType];
    // }
    return haveStore.__store[resourceType] = amount;
}

function isCreep(target){
    return target instanceof Creep || target instanceof PowerCreep;
}
function isLink(target){
    return target instanceof StructureLink;
}
function isTerminal(target){
    return target instanceof StructureTerminal;
}
/**
 * 
 * @param {AnyCreep|AnyStoreStructure|Resource|Tombstone|Ruin} src 
 * @param {AnyCreep|AnyStoreStructure} dest
 * @param {ResourceConstant} resourceType 
 * @param {Number} amount 
 * @returns {CreepActionReturnCode}
 */
export function transportResource(src, dest, resourceType = undefined, amount = undefined, shortTerm = undefined){
    if(resourceType === undefined){
        resourceType = RESOURCE_ENERGY;
    }
    if(shortTerm === undefined){
        shortTerm = false;
    }
    let ret;

    const energyAvailable = Math.min(getResourceAmount(src), getActualFreeCapacity(dest, resourceType));
    if(amount === undefined){
        amount = energyAvailable;
    }else{
        amount = Math.min(energyAvailable, amount);
    }
    switch(true){
        case isLink(src) && isLink(dest):
            ret = src.transferEnergy(dest, amount);
            break;

        case isTerminal(src) && isTerminal(dest):
            ret = src.send(resourceType, amount, dest.room);
            break;

        case isCreep(src):
            ret = src.transfer(dest, resourceType, amount);
            break;

        case isCreep(dest):
            if(src instanceof Resource){
                ret = dest.pickup(src);
                break;
            }
            ret = dest.withdraw(src, resourceType, amount);
            break;

        default:
            ret = ERR_INVALID_ARGS;
            break;
    }
    if(ret === OK){
        setResourceAmount(src, getActualResourceAmount(src)-amount, resourceType, true);
        setResourceAmount(dest, getActualResourceAmount(dest)+amount, resourceType, true);
    }else if(ret === ERR_NOT_IN_RANGE){
        if(!shortTerm){
            setResourceAmount(src, getResourceAmount(src)-amount, resourceType);
            setResourceAmount(dest, getResourceAmount(dest)+amount, resourceType);
        }
    }
    return ret;
}